using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.Text;
using System.IO;
using System.Collections;
using System.Configuration;
using System.Windows.Forms;
using System.Data.SqlClient;
using Microsoft.SqlServer.Management.Smo;

namespace PSErrorLogToDB
{
    public partial class Form1 : Form
    {
        private Filter dlgFilter;
        private string connectionString;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Splash formSplash = new Splash();
            formSplash.Show();
            Application.DoEvents();

            Settings.LoadSettings(Application.ExecutablePath + ".config");

            cbDBServer.Text = Settings.DBServer;
            cbDB.Text = Settings.DBName;
            dtStart.Value = Settings.StartDate;
            dtEnd.Value = Settings.EndDate;
            chkUseFilter.Checked = Settings.UseFilter;
            foreach (string dir in Settings.Directories)
            {
                lbDirectories.Items.Add(dir);
            }

            dlgFilter = new Filter();
            dlgFilter.ConnectionString = "Data Source=" + cbDBServer.Text + ";Initial Catalog=" + cbDB.Text + ";Integrated Security=true";
            
            formSplash.FadeForm();
            formSplash.Close();
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            Settings.DBServer = cbDBServer.Text;
            Settings.DBName = cbDB.Text;
            Settings.StartDate = dtStart.Value;
            Settings.EndDate = dtEnd.Value;
            Settings.UseFilter = chkUseFilter.Checked;
            ArrayList dirs = new ArrayList();
            foreach (string dir in lbDirectories.Items)
            {
                dirs.Add(dir);
            }
            Settings.Directories = dirs;

            Settings.SaveSettings();
        }

        private void btnBrowse_Click(object sender, EventArgs e)
        {
            if (folderBrowser.ShowDialog() == DialogResult.OK)
            {
                txtDir.Text = folderBrowser.SelectedPath;
            }
        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
            if (txtDir.Text.Length == 0) return;
            
            lbDirectories.Items.Add(txtDir.Text);
            txtDir.Text = "";
        }

        private void btnRemove_Click(object sender, EventArgs e)
        {
            if (lbDirectories.SelectedIndex == -1) return;
            
            lbDirectories.Items.RemoveAt(lbDirectories.SelectedIndex);
        }

        private void cbDBServer_DropDown(object sender, EventArgs e)
        {
            if (cbDBServer.Items.Count > 0) return;

            Cursor = Cursors.WaitCursor;

            try
            {
                SmoApplication.EnumAvailableSqlServers(false);
                DataTable dtServers = SmoApplication.EnumAvailableSqlServers(false);
                cbDBServer.Items.Clear();
                cbDB.Text = "";
                foreach (DataRow dr in dtServers.Rows)
                {
                    string sqlServerName = dr["Server"].ToString();
                    if (dr["Instance"] != null && dr["Instance"].ToString().Length > 0)
                    {
                        sqlServerName += @"\" + dr["Instance"].ToString();
                    }
                    cbDBServer.Items.Add(sqlServerName);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            finally
            {
                Cursor = Cursors.Default;
            }
        }

        private void cbDB_DropDown(object sender, EventArgs e)
        {
            Cursor = Cursors.WaitCursor;

            try
            {
                if (cbDBServer.Text.Length == 0) return;
                Server svr = new Server(cbDBServer.Text);
                cbDB.Items.Clear();
                foreach (Database db in svr.Databases)
                {
                    cbDB.Items.Add(db.Name);
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            finally
            {
                Cursor = Cursors.Default;
            }
            dlgFilter.ConnectionString = "Data Source=" + cbDBServer.Text + ";Initial Catalog=" + cbDB.Text + ";Integrated Security=true";
        }

        private void chkUseFilter_CheckedChanged(object sender, EventArgs e)
        {
            dtStart.Enabled = chkUseFilter.Checked;
            dtEnd.Enabled = chkUseFilter.Checked;
        }

        private void btnImport_Click(object sender, EventArgs e)
        {
            Cursor = Cursors.WaitCursor;

            try
            {
                if (cbDBServer.Text.Length == 0 || cbDB.Text.Length == 0) return;

                connectionString = "Data Source=" + cbDBServer.Text + ";Initial Catalog=" + cbDB.Text + ";Integrated Security=true";
                lbStatus.Items.Clear();

                using (SqlConnection cn = new SqlConnection(connectionString))
                {
                    cn.Open();

                    // Clear the log.
                    SqlCommand cmd = new SqlCommand("ClearEntries", cn);
                    cmd.CommandType = CommandType.StoredProcedure;
                    cmd.ExecuteNonQuery();

                    foreach (string dir in lbDirectories.Items)
                    {
                        Log("Searching for log files in directory " + dir);
                        if (!Directory.Exists(dir)) continue;

                        string machine = string.Empty;
                        DateTime date = DateTime.Now;
                        foreach (string logFile in Directory.GetFiles(dir, "*.log"))
                        {
                            ParseLogFileName(logFile, ref machine, ref date);
                            // Filter based upon the date in the name.
                            if ((date.Date > dtEnd.Value.Date || date.Date < dtStart.Value.Date) && chkUseFilter.Checked) continue;

                            ExtractLogInfo(cn, logFile, machine);
                            Application.DoEvents();
                        }
                    }
                }
                Log("Log file import complete.");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

            Cursor = Cursors.Default;
        }

        private bool ParseLogFileName(string logFile, ref string machine, ref DateTime date)
        {
            // String the path.
            string filename = logFile;
            int lastBackslash = logFile.LastIndexOf("\\");
            if (lastBackslash > -1)
            {
                filename = logFile.Substring(lastBackslash + 1);
            }

            int index = filename.IndexOf("-200");
            if (index == -1) return false;
            int index1 = filename.IndexOf("-", index + 1);
            if (index1 == -1) return false;

            // CHRISFIE03-20070619-1815.log
            // DL580G3-1-20070618-1610.log

            machine = filename.Substring(0, index);
            string rawDate = filename.Substring(index + 1, 8);
            string rawTime = filename.Substring(index1 + 1, 4);
            string datetime = rawDate.Substring(0, 4) + "-" + rawDate.Substring(4, 2) + "-" + rawDate.Substring(6,2) + " ";
            datetime = datetime + (rawTime.Substring(0, 2) + ":" + rawTime.Substring(2, 2));
            date = DateTime.Parse(datetime);
            return true;
        }

        private void ExtractLogInfo(SqlConnection cn, string logFile, string serverName)
        {
            try
            {
                // Create an instance of StreamReader to read from a file.
                using (StreamReader sr = new StreamReader(logFile))
                {
                    string[] columns;
                    const char separator = '\t';
                    DateTime timestamp;
                    string process;
                    string tid;
                    string area;
                    string category;
                    string eventid;
                    string level;
                    string msg;
                    string header = sr.ReadLine();
                    if (header.Substring(0, 9) != "Timestamp") return;
                    string line;
                    while ((line = sr.ReadLine()) != null)
                    {
                        IFormatProvider culture = new CultureInfo("en-US", true);

                        // Parse the line of text.
                        columns = line.Split(separator);
                        timestamp = Convert.ToDateTime(columns[0].Trim().Replace("*",""), culture);
                        process = columns[1].Trim();
                        tid = columns[2].Trim();
                        area = columns[3].Trim();
                        category = columns[4].Trim();
                        eventid = columns[5].Trim();
                        level = columns[6].Trim();
                        msg = columns[7].Trim();

                        // Insert into table.
                        SqlCommand cmd = new SqlCommand("AddEntry", cn);
                        cmd.CommandType = CommandType.StoredProcedure;
                        SqlParameter param = new SqlParameter("@Area", SqlDbType.NVarChar, 30);
                        param.Value = area;
                        cmd.Parameters.Add(param);
                        param = new SqlParameter("@Category", SqlDbType.NVarChar, 30);
                        param.Value = category;
                        cmd.Parameters.Add(param);
                        param = new SqlParameter("@Level", SqlDbType.NVarChar, 20);
                        param.Value = level;
                        cmd.Parameters.Add(param);
                        param = new SqlParameter("@Event", SqlDbType.NVarChar, 6);
                        param.Value = eventid;
                        cmd.Parameters.Add(param);
                        param = new SqlParameter("@Process", SqlDbType.NVarChar, 40);
                        param.Value = process;
                        cmd.Parameters.Add(param);
                        param = new SqlParameter("@Timestamp", SqlDbType.DateTime);
                        param.Value = timestamp;
                        cmd.Parameters.Add(param);
                        param = new SqlParameter("@TID", SqlDbType.NVarChar, 6);
                        param.Value = tid;
                        cmd.Parameters.Add(param);
                        param = new SqlParameter("@Msg", SqlDbType.NVarChar, 255);
                        param.Value = msg;
                        cmd.Parameters.Add(param);
                        param = new SqlParameter("@ServerName", SqlDbType.NVarChar, 50);
                        param.Value = serverName;
                        cmd.Parameters.Add(param);
                        param = new SqlParameter("@LogFile", SqlDbType.NVarChar, 255);
                        param.Value = logFile;
                        cmd.Parameters.Add(param);

                        cmd.ExecuteNonQuery();
                    }
                }
                Log("Imported information from log file " + logFile);
            }
            catch (Exception ex)
            {
                Log("*** Error - The file " + logFile + " could not be read.  " + ex.Message);
            }
        }

        private void Log(string msg)
        {
            lbStatus.Items.Insert(0, DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString() + " " + msg);
            if (lbStatus.Items.Count > 300) lbStatus.Items.RemoveAt(lbStatus.Items.Count - 1);
        }

        private void RefreshData()
        {
            Cursor = Cursors.WaitCursor;

            try
            {
                string connectionString = "Data Source=" + cbDBServer.Text + ";Initial Catalog=" + cbDB.Text + ";Integrated Security=true";

                DataSet dsStats = new DataSet();
                using (SqlConnection cn = new SqlConnection(connectionString))
                {
                    SqlCommand cmd = new SqlCommand("GetEntries", cn);
                    cmd.CommandType = CommandType.StoredProcedure;
                    cn.Open();

                    // Set optional SP params.
                    SqlParameter param;
                    if (dlgFilter.FilterArea)
                    {
                        param = new SqlParameter("@Area", SqlDbType.NVarChar, 30);
                        param.Value = dlgFilter.Area;
                        cmd.Parameters.Add(param);
                    }
                    if (dlgFilter.FilterCategory)
                    {
                        param = new SqlParameter("@Category", SqlDbType.NVarChar, 30);
                        param.Value = dlgFilter.Category;
                        cmd.Parameters.Add(param);
                    }
                    if (dlgFilter.FilterLevel)
                    {
                        param = new SqlParameter("@Level", SqlDbType.NVarChar, 20);
                        param.Value = dlgFilter.Level;
                        cmd.Parameters.Add(param);
                    }
                    if (dlgFilter.FilterProcess)
                    {
                        param = new SqlParameter("@Process", SqlDbType.NVarChar, 40);
                        param.Value = dlgFilter.Process;
                        cmd.Parameters.Add(param);
                    }
                    if (dlgFilter.FilterServerName)
                    {
                        param = new SqlParameter("@ServerName", SqlDbType.NVarChar, 30);
                        param.Value = dlgFilter.ServerName;
                        cmd.Parameters.Add(param);
                    }
                    if (dlgFilter.FilterTimestamp)
                    {
                        param = new SqlParameter("@StartTimestamp", SqlDbType.DateTime);
                        param.Value = dlgFilter.StartRange;
                        cmd.Parameters.Add(param);
                        param = new SqlParameter("@EndTimestamp", SqlDbType.DateTime);
                        param.Value = dlgFilter.EndRange;
                        cmd.Parameters.Add(param);
                    }
                    if (dlgFilter.Msg.Length > 0)
                    {
                        param = new SqlParameter("@Msg", SqlDbType.NVarChar, 255);
                        param.Value = dlgFilter.Msg;
                        cmd.Parameters.Add(param);
                    }

                    SqlDataReader reader = cmd.ExecuteReader();

                    string[] tables = new string[1];
                    tables[0] = "PROJECT_LOGS";
                    dsStats.Load(reader, LoadOption.OverwriteChanges, tables);
                    reader.Close();
                    dgResults.DataSource = dsStats.Tables["PROJECT_LOGS"];
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("RefreshData failed.  " + ex.Message);
            }

            Cursor = Cursors.Default;
        }

        private void btnRefresh_Click(object sender, EventArgs e)
        {
            RefreshData();
        }

        private void btnFilter_Click(object sender, EventArgs e)
        {
            if (dlgFilter.ShowDialog() == DialogResult.OK)
            {
                RefreshData();
            }
        }
    }
}